//
//  PlSInstaller.m
//  Installer
//
//  Created by ∞ on 20/12/07.
//  Copyright 2007 Emanuele Vulcano (infinite-labs.net). All rights reserved.
//

#import "PlSInstaller.h"
#import "../L0PlugSuitWire.h"
#import <Carbon/Carbon.h>
#import "NSAlert+L0Alert.h"

@implementation PlSInstaller

- (void) awakeFromNib {	
	[_mainWindow center];
	[_mainWindow makeKeyAndOrderFront:self];
	
	if (self.isAlreadyInstalled)
		[_installButton setTitle:NSLocalizedString(@"Update Now", "Title for the install button if PlugSuit is already installed and needs to be updated.")];
}

- (NSBundle*) bundleToBeInstalled {
	return [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"PlugSuit" ofType:@"prefPane"]];
}

- (NSString*) versionToBeInstalled {
	return [self.bundleToBeInstalled objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
}

- (BOOL) isAlreadyInstalled {
	return [self pathToAlreadyInstalled] != nil;
}

- (NSString*) pathToAlreadyInstalled {
	NSString* prefpanes = self.pathToPreferencePanes;
	for (NSString* item in [[NSFileManager defaultManager] directoryContentsAtPath:prefpanes]) {
		item = [prefpanes stringByAppendingPathComponent:item];
		NSBundle* b = [NSBundle bundleWithPath:item];
		if (b && [[b bundleIdentifier] isEqual:@"net.infinite-labs.PlugSuit"])
			return item;
	}
	
	return nil;
}

- (NSString*) pathToPreferencePanes {
	return [self.libraryDirectory stringByAppendingPathComponent:@"PreferencePanes"];
}

- (NSString*) libraryDirectory {
	NSArray* arr = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDirectory, YES);
	if ([arr count] == 0) return nil;
	return [arr objectAtIndex:0];
}

- (NSURL*) URLToPreferencePanes {
	return [NSURL fileURLWithPath:self.pathToPreferencePanes];
}

- (IBAction) cancelAndQuit:(id) sender {
	[NSApp terminate:self];
}

- (IBAction) revealFolder:(id) sender {
	[[NSWorkspace sharedWorkspace] openURL:[[sender clickedPathComponentCell] URL]];
}

- (IBAction) install:(id) sender {
	if (_installing) { NSBeep(); return; }
	_installing = YES;
	[_installButton setEnabled:NO];
	
	[self uninstallAndContinueIfInstalling];
}

- (void) uninstallAndContinueIfInstalling {
	L0LogS(@"check");

	NSWorkspace* ws = [NSWorkspace sharedWorkspace];
	NSFileManager* fm = [NSFileManager defaultManager];
	
	[[ws notificationCenter] addObserver:self selector:@selector(_workspaceDidEndCopy:) name:NSWorkspaceDidPerformFileOperationNotification object:nil];
	
	NSString* oldBundle;
	if (oldBundle = self.pathToAlreadyInstalled) {
		L0LogS(@"will disable already installed");
		// stop a 1.0 agent if running.
		@try {
			id <L0PlugSuitWire> wire = (id <L0PlugSuitWire>) [NSConnection rootProxyForConnectionWithRegisteredName:kL0PlugSuitConnectionName host:nil];
			if (wire) [wire shutDown];
			
			while ([NSConnection rootProxyForConnectionWithRegisteredName:kL0PlugSuitConnectionName host:nil])
				sleep(1);
		} @catch (NSException* e) {}
		
		LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
		if (loginItems) {
			L0LogS(@"Checking login items...");
			UInt32 dummy;
			NSArray* arr = (NSArray*) LSSharedFileListCopySnapshot(loginItems, &dummy);
			for (id item in arr) {
				LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef) item;
				NSURL* url = nil;
				if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &url, NULL) == noErr) {
					L0Log(@"checking at url = %@", url);
					if ([[url path] hasPrefix:oldBundle]) {
						L0LogS(@"will remove!");
						LSSharedFileListItemRemove(loginItems, itemRef);
					}
				}
			}
			[arr release];
		}
		CFRelease(loginItems);
		
		BOOL isPs15Running = NO;
		@try {
			isPs15Running = ([NSConnection rootProxyForConnectionWithRegisteredName:@"net.infinite-labs.PlugSuit.PRIVATE.RunMarker" host:nil] != nil);
		} @catch (NSException* ex) {}
		
		L0Log(@"is ps 1.5 running = %d", isPs15Running);
		
		if (isPs15Running) {
		// stop a 1.5 agent if running
			NSString* ps15Plist = [[self.libraryDirectory stringByAppendingPathComponent:@"LaunchAgents"] stringByAppendingPathComponent:@"net.infinite-labs.PlugSuit.Agent.plist"];
		
			if ([fm fileExistsAtPath:ps15Plist]) {
				NSTask* task = [NSTask launchedTaskWithLaunchPath:@"/bin/launchctl" arguments:
				 [NSArray arrayWithObjects:@"unload", @"-w", @"-S", @"Aqua", ps15Plist, nil]];
				[task waitUntilExit];
				
				L0Log(@"PS 1.5 stopped with launchctl return code = %d", [task terminationStatus]);
			}
		}
		
		[self trashOldBundle];
	} else
		[self copyNewBundle];
}

- (IBAction) uninstall:(id) sender {
	NSAlert* alert = [NSAlert alertNamed:@"PlSUninstallAsk"];
	[alert beginSheetModalForWindow:_mainWindow modalDelegate:self didEndSelector:@selector(_uninstallAlert:result:contextInfo:) contextInfo:NULL];
}

- (void) _uninstallAlert:(NSAlert*) alert result:(NSInteger) res contextInfo:(void*) nothing {
	[[alert window] orderOut:self];
	if (res == NSAlertSecondButtonReturn) return;

	_installing = NO;
	[self uninstallAndContinueIfInstalling];
}

- (BOOL) systemPreferencesIsRunning {
	for (NSDictionary* app in [[NSWorkspace sharedWorkspace] launchedApplications]) {
		if ([[app objectForKey:@"NSApplicationBundleIdentifier"] isEqual:@"com.apple.systempreferences"])
			return YES;
	}
	
	return NO;
}

- (void) trashOldBundle {
	if (self.systemPreferencesIsRunning) {
		NSAppleScript* script = [[NSAppleScript alloc] initWithSource:@"tell app \"System Preferences\" to quit"];
		NSDictionary* dict = nil;
		[script executeAndReturnError:&dict];
		
		if (dict) {
			NSLog(@"AppleScript error while trying to make System Preferences quit: %@", [dict descriptionInStringsFileFormat]);
		}
		
		[script release];
	}
	
	// NSInteger i;
	NSString* oldBundle = self.pathToAlreadyInstalled;
	
	/* if (![[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:[oldBundle stringByDeletingLastPathComponent] destination:@"" files:[NSArray arrayWithObject:[oldBundle lastPathComponent]] tag:&i]) {
		NSError* err = [NSError errorWithDomain:NSPOSIXErrorDomain code:EIO userInfo:nil];
		[NSApp presentError:err modalForWindow:_mainWindow delegate:self didPresentSelector:@selector(_trashOldBundleErrorRecovered:contextInfo:) contextInfo:NULL];
	} */
	
	FSRef ref;
	if (!CFURLGetFSRef((CFURLRef) [NSURL fileURLWithPath:oldBundle], &ref)) {
		NSError* err = [NSError errorWithDomain:NSPOSIXErrorDomain code:EIO userInfo:nil];
		[NSApp presentError:err modalForWindow:_mainWindow delegate:self didPresentSelector:@selector(_trashOldBundleErrorRecovered:contextInfo:) contextInfo:NULL];
		return;
	}
	
	OSStatus errCode;
	if ((errCode = FSMoveObjectToTrashSync(&ref, NULL, kFSFileOperationDefaultOptions)) != noErr) {
		NSError* err = [NSError errorWithDomain:NSOSStatusErrorDomain code:errCode userInfo:nil];
		[NSApp presentError:err modalForWindow:_mainWindow delegate:self didPresentSelector:@selector(_trashOldBundleErrorRecovered:contextInfo:) contextInfo:NULL];
		return;
	}
	
	if (_installing)
		[self copyNewBundle];
	else
		[self notifyUninstalled];
}

- (void) _trashOldBundleErrorRecovered:(BOOL) recovered contextInfo:(void*) nothing {
	if (recovered) [self trashOldBundle];
}

/* - (void) _workspaceDidEndTrashing:(NSNotification*) notif {
	if (_installing)
		[self copyNewBundle];
	else
		[self notifyUninstalled];
} */

- (void) notifyUninstalled {
	NSAlert* alert = [NSAlert alertNamed:@"PlSUninstallNotice"];
	[alert beginSheetModalForWindow:_mainWindow modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
}

- (void) copyNewBundle {
	NSError* err = nil;
	NSString* target = [[self.bundleToBeInstalled bundlePath] lastPathComponent];
	target = [self.pathToPreferencePanes stringByAppendingPathComponent:target];
	
	if (![[NSFileManager defaultManager] copyItemAtPath:[self.bundleToBeInstalled bundlePath] toPath:target error:&err]) {
		[NSApp presentError:err modalForWindow:_mainWindow delegate:self didPresentSelector:@selector(_copyNewBundleErrorRecovered:contextInfo:) contextInfo:NULL];
	} else {
		CFPreferencesSetAppValue(CFSTR("PlSShouldTryEnabling"), kCFBooleanTrue, CFSTR("net.infinite-labs.PlugSuit"));
		CFPreferencesAppSynchronize(CFSTR("net.infinite-labs.PlugSuit"));
		[[NSWorkspace sharedWorkspace] openFile:target];
		[NSApp terminate:self];
	}

}

- (void) _copyNewBundleErrorRecovered:(BOOL) recovered contextInfo:(void*) nothing {
	if (recovered) [self copyNewBundle];
}

@end
